home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CTOOLS10.ARJ / GETOPT.C < prev    next >
C/C++ Source or Header  |  1991-12-31  |  12KB  |  358 lines

  1. /****************************************************************************
  2. *
  3. *                    Copyright (C) 1991 Kendall Bennett.
  4. *                            All rights reserved.
  5. *
  6. * Filename:        $RCSfile: getopt.c $
  7. * Version:        $Revision: 1.5 $
  8. *
  9. * Language:        ANSI C
  10. * Environment:    any
  11. *
  12. * Description:    This module contains code to parse the command line,
  13. *                extracting options and parameters in standard System V
  14. *                style.
  15. *
  16. * $Id: getopt.c 1.5 91/12/31 19:39:55 kjb Exp $
  17. *
  18. * Revision History:
  19. * -----------------
  20. *
  21. * $Log:    getopt.c $
  22. * Revision 1.5  91/12/31  19:39:55  kjb
  23. * Modified include file directories.
  24. * Revision 1.4  91/10/28  03:17:02  kjb
  25. * Ported to the Iris.
  26. * Revision 1.3  91/09/24  19:48:05  kjb
  27. * Added getargs() to parse the entire command line and converting the
  28. * parameters to the types specified in a table of options.
  29. * Added routine print_desc() to print the option description from the
  30. * table to the standard output device.
  31. * Revision 1.2  91/09/03  18:27:52  ROOT_DOS
  32. * Ported to UNIX.
  33. * Revision 1.1  91/08/16  10:45:36  ROOT_DOS
  34. * Initial revision
  35. ****************************************************************************/
  36.  
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <ctype.h>
  40. #include "debug.h"
  41. #include "getopt.h"
  42.  
  43. /*------------------------- Global variables ------------------------------*/
  44.  
  45. int        nextargv    =    1;            /* Index into argv array            */
  46. char    *nextchar    =    NULL;        /* Pointer to next character        */
  47.  
  48. /*-------------------------- Implementation -------------------------------*/
  49.  
  50. #ifdef    __MSDOS__
  51. #define    IS_SWITCH_CHAR(c)        (c == '-') || (c == '/')
  52. #define    IS_NOT_SWITCH_CHAR(c)    (c != '-') && (c != '/')
  53. #else
  54. #define    IS_SWITCH_CHAR(c)        (c == '-')
  55. #define    IS_NOT_SWITCH_CHAR(c)    (c != '-')
  56. #endif
  57.  
  58. PUBLIC int getopt(int argc,char **argv,char *format,char **argument)
  59. /****************************************************************************
  60. *
  61. * Function:        getopt
  62. * Parameters:    argc        -    Value passed to program through argc
  63. *                                variable in the function main.
  64. *                argv        -     Pointer to the argv array that is passed to
  65. *                                the program in function main.
  66. *                format        -    A string representing the expected format
  67. *                                of the command line options that need to be
  68. *                                parsed.
  69. *                argument    -     Pointer to optional argument on command
  70. *                                line.
  71. *
  72. * Returns:        Character code representing the next option parsed from the
  73. *                command line by getopt. Returns ALLDONE (-1) when there are
  74. *                no more parameters to be parsed on the command line,
  75. *                PARAMETER (-2) when the argument being parsed is a
  76. *                parameter and not an option switch and lastly INVALID (-3)
  77. *                if an error occured while parsing the command line.
  78. *
  79. * Description:    Function to parse the command line option switches in
  80. *                UNIX System V style. When getopt is called, it returns the
  81. *                character code of the next valid option that is parsed from
  82. *                the command line as specified by the Format string. The
  83. *                format string should be in the following form:
  84. *
  85. *                        "abcd:e:f:"
  86. *
  87. *                where a,b and c represent single switch style options and
  88. *                the character code returned by getopt is the only value
  89. *                returned. Also d, e and f represent options that expect
  90. *                arguments immediately after them on the command line. The
  91. *                argument that follows the option on the command line is
  92. *                returned via a reference in the pointer argument. Thus
  93. *                a valid command line for this format string might be:
  94. *
  95. *                    myprogram -adlines /b /f format infile outfile
  96. *
  97. *                where a and b will be returned as single character options
  98. *                with no argument, while d is returned with the argument
  99. *                lines and f is returned with the argument format. Note that
  100. *                either UNIX style or MS-DOS command switches may be used
  101. *                interchangeably under MSDOS, but under UNIX only the UNIX
  102. *                style switches are supported.
  103. *
  104. *                When getopt returns with PARAMETER (we attempted to parse
  105. *                a paramter, not an option), the global variable NextArgv
  106. *                will hold an index in the argv array to the argument on the
  107. *                command line AFTER the options, ie in the above example the
  108. *                string 'infile'. If the parameter is successfully used,
  109. *                NextArgv should be incremented and getopt can be called
  110. *                again to parse any more options. Thus you can also have
  111. *                options interspersed throught the command line. eg:
  112. *
  113. *                    myprogram -adlines infile /b outfile /f format
  114. *
  115. *                can be made to be a valid form of the above command line.
  116. *
  117. ****************************************************************************/
  118. {
  119.     char    ch;
  120.     char    *formatchar;
  121.  
  122.     if (argc > nextargv) {
  123.         if (nextchar == NULL) {
  124.             nextchar = argv[nextargv];        /* Index next argument         */
  125.             if(nextchar == NULL) {
  126.                 nextargv++;
  127.                 return ALLDONE;                /* No more options             */
  128.                 }
  129.             if(IS_NOT_SWITCH_CHAR(*nextchar)) {
  130.                 nextchar = NULL;
  131.                 return PARAMETER;            /* We have a parameter         */
  132.                 }
  133.             nextchar++;                    /* Move past switch operator    */
  134.             if(IS_SWITCH_CHAR(*nextchar)) {
  135.                 nextchar = NULL;
  136.                 return INVALID;                /* Ignore rest of line         */
  137.                 }
  138.             }
  139.  
  140.         if ((ch = *(nextchar++)) == 0) {
  141.             nextchar = NULL;
  142.             return INVALID;                    /* No options on line         */
  143.             }
  144.  
  145.         if (ch == ':' ||  (formatchar = strchr(format, ch)) == NULL)
  146.             return INVALID;
  147.  
  148.         if (*(++formatchar) == ':') {    /* Expect an argument after option */
  149.             nextargv++;
  150.             if (*nextchar == 0) {
  151.                 if (argc <= nextargv)
  152.                     return INVALID;
  153.                 nextchar = argv[nextargv++];
  154.                 }
  155.             *argument = nextchar;
  156.             nextchar = NULL;
  157.             }
  158.         else {                        /* We have a switch style option    */
  159.             if (*nextchar == 0) {
  160.                 nextargv++;
  161.                 nextchar = NULL;
  162.             }
  163.             *argument = NULL;
  164.             }
  165.         return ch;                    /* return the option specifier         */
  166.         }
  167.     nextchar = NULL;
  168.     nextargv++;
  169.     return ALLDONE;                    /* no arguments on command line     */
  170. }
  171.  
  172. PRIVATE int parse_option(Option *optarr,char *argument)
  173. /****************************************************************************
  174. *
  175. * Function:        parse_option
  176. * Parameters:    optarr        - Description for the option we are parsing
  177. *                argument    - String to parse
  178. * Returns:        INVALID on error, ALLDONE on success.
  179. *
  180. * Description:    Parses the argument string depending on the type of argument
  181. *                that is expected, filling in the argument for that option.
  182. *                Note that to parse a string, we simply return a pointer
  183. *                to argument.
  184. *
  185. ****************************************************************************/
  186. {
  187.     int        num_read = 0;
  188.  
  189.     switch ((int)(optarr->type)) {
  190.         case OPT_INTEGER:
  191.             num_read = sscanf(argument,"%d",optarr->arg);
  192.             break;
  193.         case OPT_HEX:
  194.             num_read = sscanf(argument,"%x",optarr->arg);
  195.             break;
  196.         case OPT_OCTAL:
  197.             num_read = sscanf(argument,"%o",optarr->arg);
  198.             break;
  199.         case OPT_UNSIGNED:
  200.             num_read = sscanf(argument,"%u",optarr->arg);
  201.             break;
  202.         case OPT_LINTEGER:
  203.             num_read = sscanf(argument,"%ld",optarr->arg);
  204.             break;
  205.         case OPT_LHEX:
  206.             num_read = sscanf(argument,"%lx",optarr->arg);
  207.             break;
  208.         case OPT_LOCTAL:
  209.             num_read = sscanf(argument,"%lo",optarr->arg);
  210.             break;
  211.         case OPT_LUNSIGNED:
  212.             num_read = sscanf(argument,"%lu",optarr->arg);
  213.             break;
  214.         case OPT_FLOAT:
  215.             num_read = sscanf(argument,"%f",optarr->arg);
  216.             break;
  217.         case OPT_DOUBLE:
  218.             num_read = sscanf(argument,"%lf",optarr->arg);
  219.             break;
  220.         case OPT_LDOUBLE:
  221.             num_read = sscanf(argument,"%Lf",optarr->arg);
  222.             break;
  223.         case OPT_STRING:
  224.             num_read = 1;            /* This always works    */
  225.             *((char**)optarr->arg) = argument;
  226.             break;
  227.         default:
  228.             return INVALID;
  229.         }
  230.  
  231.     if (num_read == 0)
  232.         return INVALID;
  233.     else
  234.         return ALLDONE;
  235. }
  236.  
  237. PUBLIC int getargs(int argc,char *argv[],int num_opt,Option optarr[],
  238.                    int (*do_param)(char *param,int num))
  239. /****************************************************************************
  240. *
  241. * Function:        getargs
  242. * Parameters:    argc        - Number of arguments on command line
  243. *                argv        - Array of command line arguments
  244. *                num_opt        - Number of options in option array
  245. *                optarr        - Array to specify how to parse the command line
  246. *                do_param    - Routine to handle a command line parameter
  247. * Returns:        ALLDONE, INVALID or HELP
  248. *
  249. * Description:    Function to parse the command line according to a table of
  250. *                options. This routine calls getopt above to parse each
  251. *                individual option and attempts to parse each option into
  252. *                a variable of the specified type. The routine can parse
  253. *                integers and long integers in either decimal, octal,
  254. *                hexadecimal notation, unsigned integers and unsigned longs,
  255. *                strings and option switches. Option switches are simply
  256. *                boolean variables that get turned on if the switch was
  257. *                parsed.
  258. *
  259. *                Parameters are extracted from the command line by calling
  260. *                a user supplied routine do_param() to handle each parameter
  261. *                as it is encountered. The routine do_param() should accept
  262. *                a pointer to the parameter on the command line and an
  263. *                integer representing how many parameters have been
  264. *                encountered (ie: 1 if this is the first parameter, 10 if
  265. *                it is the 10th etc), and return ALLDONE upon successfully
  266. *                parsing it or INVALID if the parameter was invalid.
  267. *
  268. *                We return either ALLDONE if all the options were
  269. *                successfully parsed, INVALID if an invalid option was
  270. *                encountered or HELP if any of -h, -H or -? were present
  271. *                on the command line.
  272. *
  273. ****************************************************************************/
  274. {
  275.     int        i,opt;
  276.     char    *argument;
  277.     int        param_num = 1;
  278.     char    cmdstr[MAXARG*2 + 4];
  279.  
  280.     /* Build the command string from the array of options    */
  281.  
  282.     strcpy(cmdstr,"hH?");
  283.     for (i = 0,opt = 3; i < num_opt; i++,opt++) {
  284.         cmdstr[opt] = optarr[i].opt;
  285.         if (optarr[i].type != OPT_SWITCH) {
  286.             cmdstr[++opt] = ':';
  287.             }
  288.         }
  289.     cmdstr[opt] = '\0';
  290.  
  291.     while (true) {
  292.         opt = getopt(argc,argv,cmdstr,&argument);
  293.         switch (opt) {
  294.             case 'H':
  295.             case 'h':
  296.             case '?':
  297.                 return HELP;
  298.             case ALLDONE:
  299.                 return ALLDONE;
  300.             case INVALID:
  301.                 return INVALID;
  302.             case PARAMETER:
  303.                 if (do_param == NULL)
  304.                     return INVALID;
  305.                 if (do_param(argv[nextargv],param_num) == INVALID)
  306.                     return INVALID;
  307.                 nextargv++;
  308.                 param_num++;
  309.                 break;
  310.             default:
  311.  
  312.                 /* Search for the option in the option array. We are
  313.                  * guaranteed to find it.
  314.                  */
  315.  
  316.                 for (i = 0; i < num_opt; i++) {
  317.                     if (optarr[i].opt == opt)
  318.                         break;
  319.                     }
  320.                 if (optarr[i].type == OPT_SWITCH)
  321.                     *((bool*)optarr[i].arg) = true;
  322.                 else {
  323.                     if (parse_option(&optarr[i],argument) == INVALID)
  324.                         return INVALID;
  325.                     }
  326.                 break;
  327.             }
  328.         }
  329. }
  330.  
  331. PUBLIC void print_desc(int num_opt,Option optarr[])
  332. /****************************************************************************
  333. *
  334. * Function:        print_desc
  335. * Parameters:    num_opt    - Number of options in the table
  336. *                optarr    - Table of option descriptions
  337. *
  338. * Description:    Prints the description of each option in a standard format
  339. *                to the standard output device. The description for each
  340. *                option is obtained from the table of options.
  341. *
  342. ****************************************************************************/
  343. {
  344.     int        i;
  345.  
  346.     for (i = 0; i < num_opt; i++) {
  347.         if (optarr[i].type == OPT_SWITCH)
  348.             printf("  -%c       %s\n",optarr[i].opt,optarr[i].desc);
  349.         else
  350.             printf("  -%c<arg>  %s\n",optarr[i].opt,optarr[i].desc);
  351.         }
  352. }
  353.